#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;

string EJECUTABLE = "main";
string TESTFILE = "test.out";

string BISECCION = "1";
string NEWTON = "2";
string BISECCIONNEWTON = "3";
string ALTURAMAXIMA = "4";
string ENERGIAMECANICA = "5";

string linea(string tipoDeTest, double precision, double h, double vi, double m, double cr, double fr, double ErrorNewton, double ErrorBiseccion, string fileName)
{
	stringstream ss;

	// Orden de los parametros tipoDeTest, precision, h, vi, m, cr, fr, ErrorNewton, ErrorBiseccion, fileName.
	ss << "./" << EJECUTABLE << " " << tipoDeTest << " " << precision << " " << h << " " << vi << " " << m << " " << cr << " " << fr << " " << ErrorNewton << " " << ErrorBiseccion << " " << fileName;

	return ss.str();
}

void testFr(string tipoDeTest, double precision, double h, double vi, double m, double cr, double frInicial, double frFinal, double frAumento, double ErrorNewton, double ErrorBiseccion, string fileName)
{
	ofstream myfile;
	myfile.open(TESTFILE.c_str(), ios::out | ios::app);


	double frVariable = frInicial;
	while (frVariable < frFinal)
	{
		myfile << linea(tipoDeTest, precision, h, vi, m, cr, frVariable, ErrorNewton, ErrorBiseccion, fileName) << endl;
		frVariable = frVariable + frAumento;
	}

	myfile.close();
}

void testCr(string tipoDeTest, double precision, double h, double vi, double m, double crInicial, double crFinal, double crAumento, double fr, double ErrorNewton, double ErrorBiseccion, string fileName)
{
	ofstream myfile;
	myfile.open(TESTFILE.c_str(), ios::out | ios::app);


	double crVariable = crInicial;
	while (crVariable < crFinal)
	{
		myfile << linea(tipoDeTest, precision, h, vi, m, crVariable, fr, ErrorNewton, ErrorBiseccion, fileName) << endl;
		crVariable = crVariable + crAumento;
	}

	myfile.close();
}

void testPrecision(string tipoDeTest, double precisionInicial, double precisionFinal, double precisionAumento, double h, double vi, double m, double cr, double fr, double ErrorNewton, double ErrorBiseccion, string fileName)
{
	ofstream myfile;
	myfile.open(TESTFILE.c_str(), ios::out | ios::app);

	double precisionVariable = precisionInicial;

	while (precisionVariable < precisionFinal)
	{
//		stringstream fileNamess;
//		fileNamess << "precision" << precisionVariable << ".out";
//		fileName = fileNamess.str();

		myfile << linea(tipoDeTest, precisionVariable, h, vi, m, cr, fr, ErrorNewton, ErrorBiseccion, fileName) << endl;
		precisionVariable = precisionVariable + precisionAumento;
	}

	myfile.close();
}

void testNewton(string tipoDeTest, double precision, double h, double vi, double m, double cr, double fr, double ErrorNewtonInicial, double ErrorNewtonFinal, double ErrorNewtonAumento, double ErrorBiseccion, string fileName)
{
	ofstream myfile;
	myfile.open(TESTFILE.c_str(), ios::out | ios::app);

	double ErrorNewtonVariable = ErrorNewtonInicial;

	while (ErrorNewtonVariable > ErrorNewtonFinal)
	{
		myfile << linea(tipoDeTest, precision, h, vi, m, cr, fr, ErrorNewtonVariable, ErrorBiseccion, fileName) << endl;
		ErrorNewtonVariable = ErrorNewtonVariable * ErrorNewtonAumento;
	}

	myfile.close();
}

void testBiseccion(string tipoDeTest, double precision, double h, double vi, double m, double cr, double fr, double ErrorNewton, double ErrorBiseccionInicial, double ErrorBiseccionFinal, double ErrorBiseccionAumento, string fileName)
{
	ofstream myfile;
	myfile.open(TESTFILE.c_str(), ios::out | ios::app);

	double ErrorBiseccionVariable = ErrorBiseccionInicial;

	while (ErrorBiseccionVariable > ErrorBiseccionFinal)
	{
		myfile << linea(tipoDeTest, precision, h, vi, m, cr, fr, ErrorNewton, ErrorBiseccionVariable, fileName) << endl;
		ErrorBiseccionVariable = ErrorBiseccionVariable * ErrorBiseccionAumento;
	}

	myfile.close();
}

void testBiseccionNewton(string tipoDeTest, double precision, double h, double vi, double m, double cr, double fr, double ErrorInicial, double ErrorFinal, double ErrorAumento, string fileName)
{
	ofstream myfile;
	myfile.open(TESTFILE.c_str(), ios::out | ios::app);

	double ErrorVariable = ErrorInicial;

	while (ErrorVariable > ErrorFinal)
	{
		myfile << linea(tipoDeTest, precision, h, vi, m, cr, fr, ErrorVariable, ErrorVariable, fileName) << endl;
		ErrorVariable = ErrorVariable * ErrorAumento;
	}

	myfile.close();
}

int main() {
	// Valores seteados por default.
	double precision = 52;
    double precisionInicial = 0.0;
    double precisionFinal = 1;
	double precisionAumento = 0.1;
	double h = 19.62;
	double vi = 150.0;
	double m = 15.0;
	double cr = 0.0;
	double crInicial = 0.0;
	double crFinal = 0.0;
	double crAumento = 0.0;
	double fr = 0.0;
	double frInicial = 0.0;
	double frFinal = 0.0;
	double frAumento = 0.0;
    double errInicial = 0.0;
    double errFinal = 0.0;
    double errAumento = 0.0;
	double ErrorNewton = 0.0001;
	double ErrorBiseccion = 0.0001;
	string fileName;

	// Variacion de cr usando biseccion.
	fileName = "biseccion.out";
	crInicial = 0.0;
	crFinal = 1;
	crAumento = 0.1;
	testCr(BISECCION, precision, h, vi, m, crInicial, crFinal, crAumento, fr, ErrorNewton, ErrorBiseccion, fileName);

	// Variacion de cr usando newton.
	fileName = "newton.out";
	crInicial = 0.0;
	crFinal = 1;
	crAumento = 0.1;
	testCr(NEWTON, precision, h, vi, m, crInicial, crFinal, crAumento, fr, ErrorNewton, ErrorBiseccion, fileName);

	// Variacion de fr usando altura.
	fileName = "altura.out";
	frInicial = 0.0;
	frFinal = 1;
	frAumento = 0.1;
    cr = 0.1;
	testFr(ALTURAMAXIMA, precision, h, vi, m, cr, frInicial, frFinal, frAumento, ErrorNewton, ErrorBiseccion, fileName);

	// Variacion de cr usando altura.
	fileName = "altura.out";
    fr = 0.5;
	crInicial = 0.1;
	crFinal = 1;
	crAumento = 0.1;
	testCr(ALTURAMAXIMA, precision, h, vi, m, crInicial, crFinal, crAumento, fr, ErrorNewton, ErrorBiseccion, fileName);

    // Variacion de precision usando newton.
	fileName = "precision.out";
	precisionInicial = 5;
    precisionFinal = 52;
	precisionAumento = 1;
	fr = 0.5;
	cr = 19;
    testPrecision(NEWTON, precisionInicial, precisionFinal, precisionAumento, h, vi, m, cr, fr, ErrorNewton, ErrorBiseccion, fileName);

    // Variacion de error usando biseccion sin rozamiento.
	fileName = "errorBiseccion.out";
	errInicial = 0.1;
	errFinal = 0.000000001;
	errAumento = 0.1;
    fr = 0.5;
    cr = 19;
	testBiseccion(BISECCION, precision, h, vi, m, cr, fr, ErrorNewton, errInicial, errFinal, errAumento, fileName);

    // Variacion de error usando newton sin rozamiento.
	fileName = "errorNewton.out";
	errInicial = 0.1;
	errFinal = 0.000000001;
	errAumento = 0.1;
    fr = 0.5;
    cr = 19;
	testNewton(NEWTON, precision, h, vi, m, cr, fr, errInicial, errFinal, errAumento, ErrorBiseccion, fileName);

    // Variacion de error usando biseccion y newton sin rozamiento.
	fileName = "errorBiseccionNewton.out";
	errInicial = 0.1;
	errFinal = 0.000000001;
	errAumento = 0.1;
    fr = 0.5;
    cr = 19;
	testBiseccionNewton(NEWTON, precision, h, vi, m, cr, fr, errInicial, errFinal, errAumento, fileName);

	return 0;
}
